/**
*
* @fileOverview  Definition for the base namespaces, classed and methods to use in the library
*
* @author WHL Member
*/

/**
* @namespace This is a base namespace for all classes/objects in library.
*/
var Tut = {};

/**
* Get DOM elements reply on Id
*
* @memberOf Tut
* @param {String} Element Id, can passed many element id
* @returns {Dom Element|Array}
*/
Tut.$ = function(element) {
    if (!Object.isUndefined(arguments)) {
        if (arguments.lenght > 1) {
            var elements = [];
            for (var i=0; i< arguments.lenght; i++) {
                elements.push(Tut.$(arguments[i]));
            }
            return elements;
        }
    }
    if (Object.isString(element)) {
        return document.getElementById(element);
    }
};

/**
*  Copy properties of a object for other object
*
* @lends Object
* @param {object} source object
* @param {object} destination object
* @returns {Object}
*/
Object.extend = function(destination, source) {
    for (var key in source) {
        destination[key] = source[key];
    }
    return destination;
};

/**
* Extend properties, methods for the built-in object : Object.
*/
(function() {
    Object.extend(Object, /** @lends Object */{		
        /**
        * Get class name of object
        * @param {object} object
        * @returns {String} Class Name
        */
        getClassName: function(object) {
            var objString = Object.prototype.toString.call(object);
            return objString.match(/^\[object\s(.*)\]$/)[1];
        },
        /**
        * Check the variable is underfined type or not.
        * @param {object} object
        * @returns {Boolean} Return true if object is of undefined type, otherwise return false
        */
        isUndefined: function(object) {
            return (typeof object === 'undefined');
        },
        /**
        * Check the variable is number or not
        * @param {object} object
        * @returns {Boolean} Return true if object is of number type, otherwise return false
        */
        isNumber: function(object) {
            return (Object.getClassName(object) === 'Number');
        },
        /**
        * Check the variable is string or not
        * @param {object} object
        * @returns {Boolean} Return true if object is of string type, otherwise return false
        */
        isString: function(object) {
            return (Object.getClassName(object) === 'String');
        },
        /**
        * Check the variable is array or not
        * @param {object} object
        * @returns {Boolean} Return true if object is of array type, otherwise return false
        */
        isArray: function(object) {
            return (Object.getClassName(object) === 'Array');
        },
        /**
        * Check the variable is a function or not
        * @param {object} object
        * @returns {Boolean} Return true if object is a function, otherwise return false
        */
        isFunction: function(object) {
            return (typeof object === 'function');
        },
        isObject: function(object) {
            return (typeof object === 'object');
        },
        /**
        * Get all keys of the object
        * @param {object} object
        * @retuns {Array} Array keys
        */
        getKeys: function(object) {
            var keys = [];
            for (var key in object) {
                keys.push(key);
            }
            return keys;
        },
        /**
        * Get all keys of the object
        * @param {object} object
        * @retuns {Array} Array keys
        */
        getValues: function(object) {
            var values = [];
            for (var key in object) {
                values.push(object[key]);
            }
            return values;
        }
        //More here ...

    });
})();

/**
* @namespace Tut.Class This object works as a static class that Contains properties, methods
* and classes that related to classes.
*/
Tut.Class = {};
/**
* Extend more functions for Tut.Class object
*/
Object.extend(Tut.Class, {
    /**
    * Inherit a class.
    * @memberOf Tut.Class
    * @param {Function} subClass Constructor function of sub class
    * @param {Function} superClass Constructor function of super class
    */
    inherit: function(subClass, superClass){
        var F = function(){};
        F.prototype = superClass.prototype;
        subClass.prototype = new F();
        //Reset the constructor for subClass
        subClass.prototype.constructor = subClass;
        //Add superClass property for child Class so child can reference to parent class
        subClass.superClass = superClass.prototype;
        if(superClass.prototype.constructor == Object.prototype.constructor) {
            superClass.prototype.constructor = superClass;
        }
    },
    /**
    * Add new object for creating the namespace. Can add many namespaces
    * For example: Ns1.Ns2..... -> will add namespace Ns1, then add Ns2 to Ns1, ...
    * @memberOf Tut.Class
    * @param {String} namespace Namespace name
    * @returns {object}
    */
    addNamespace: function(namespace) {
        if (!namespace) {
            return;
        }
        var ns = namespace.split('.');
        var target = null;
        for (var i=0; i<ns.length; i++) {
            if (target == null) {
                target = window[ns[i]] ? window[ns[i]] : window[ns[i]] = {};
            } else {
                target = target[ns[i]] ? target[ns[i]] : target[ns[i]] = {};
            }
        }
        return target;
    }
});

/**
* Extend properties, methods for the built-in class Function
*/
(function(){
    /**
    * Convert arguments to array
    * @param {Array} args
    * @returns {Array} Actual Array
    */
    function toArray(args) {
        var array = [];
        for (var i=0; i<args.length; i++) {
            array.push(args[i]);
        }
        return array;
    }
    Object.extend(Function.prototype, /** @lends Function.prototype */ {
        /**
        * Add object for the function's current context
        * @param {object} object It will be this in function
        * @returns {Function} Return an annonymous function with object is the this context in function
        */
        bind: function(object) {
            if (arguments.length < 2 && Object.isUndefined(arguments[0])) {
                return this;
            }
            var method = this;
            var args = Array.prototype.slice.call(arguments, 1);
            return function() {
                return method.apply(object, args.concat(toArray(arguments)));
            };
        },
        /**
        * Add object for the function's current context
        * @param {object} object It will be this object of function
        * @returns {Function} Return an annonymous function with object is the this context in function
        * and event object is passed throught the first parameter.
        */
        bindEvent: function(object) {
            var method = this;
            var args = Array.prototype.slice.call(arguments, 1);
            return function(event) {
                var args1 = Array.prototype.slice.call(arguments, 1);
                args = args.concat(args1);
                return method.apply(object, args.concat([event || window.event]));
            };
        }

        //Add more methods for Function class ...
    });
})();

/**
* Add more methods for the built-in class: String.
*/
Object.extend(String.prototype, /** @lends String.prototype */ {
    /**
    * trim left and right whitespace of a string
    * @returns {String}
    */
    trim: function() {
        return this.replace(/^\s+/g, '').replace(/\s+$/g,'');
    },
    /**
    * Validate email
    * @returns {Boolean}
    */
    isEmail: function() {
        var regEx = new RegExp('^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]{2,6}$');
        return regEx.test(this);
    },
    /**
    * Auto-URL from a string
    * @param {String} val Raw name
    * @returns {String} URL
    */
    autoUrl: function() {
        var url = this.replace(/[^0-9a-zA-Z_\-]/g, " ");
        url = url.replace(/\s\s+/g, " ").trim();
        url = url.replace(/\s/g, "_");
        return url;
    },
    /**
    * Auto-URL from a string
    * @param {String} val Raw name
    * @returns {String} URL
    */
    autoUrl2: function() {
        var url = this.replace(/[^0-9a-zA-Z]/g, " ");
        url = url.replace(/\s\s+/g, " ").trim();
        url = url.replace(/\s/g, "-");
        return url.toLowerCase();
    },
	/**
    * Auto Upper Case from a string
    * @param {String} val Raw name
    * @returns {String} URL
    */
	autoUpperCase: function() {
		var url = this.autoUrl();
		return url.toUpperCase();
	},
    /**
    * Compare with a string
    *
    * @param {String} str
    * @returns {Boolean}
    */
    compare: function(str) {
        return (this == str);
    }
});
/**
* Add more static methods for the built-in class: Number.
*/

/**
* Compare to number
*
* @lends Object
* @param {Number} num1
* @param {Number} num2
* @returns {Number} 0: Equal, < 0: This number is less than the number, > 0: Is greater than
*/
Number.compareFloat = function(num1, num2) {
    num1 = parseFloat(num1);
    num2 = parseFloat(num2);
    if (num1 == num2) return 0;
    else if (num1 < num2) return -1;
    else return 1;
};

/**
* Convert a number to Date object
*
* @returns {Object} the Date object
*/
Number.prototype.toDate = function() {
    return(new Date(this*1000));
};
/**
* Add more static methods for the built-in class: Date.
*/
/**
* Compare two string date
*
* @lend Date
* @param {String} date1
* @param {String} date2
* @param {Number} type 1: the input date in format mm dd yyyy, 0: dd mm yyyy
* @returns {Number} 0: Equal, < 0: Lest than, > 0: greater than
*/
Date.compareDate = function(date1, date2, type) {
    if (!type) type=0;
    var dateInput=(type==1)?1:0;
    var dateType=new Array();
    dateType[0]=/^\d{1,2}(\-|\/|\.|\s)\d{1,2}(\-|\/|\.|\s)\d+$/;    //date format dd mm yyyy
    dateType[1]=/^\d{1,2}(\-|\/|\.|\s)\d{1,2}(\-|\/|\.|\s)\d+$/;    //date format mm dd yyyy

    if (date1.search(dateType[dateInput])==-1||date2.search(dateType[dateInput])==-1) throw 'Invalid date';

    var seperator1=(date1.indexOf("-")!=-1)?"-":(date1.indexOf("/")!=-1)?"/":(date1.indexOf(".")!=-1)?".":(date1.indexOf(" ")!=-1)?" ":"";
    var seperator2=(date2.indexOf("-")!=-1)?"-":(date2.indexOf("/")!=-1)?"/":(date2.indexOf(".")!=-1)?".":(date2.indexOf(" ")!=-1)?" ":"";

    if (seperator1==""||seperator2=="") throw 'Invalid date';

    var dateArr1=date1.split(seperator1);
    var dateArr2=date2.split(seperator2);

    if (dateArr1.length!=3||dateArr2.length!=3) throw 'Invalid date';

    if (dateInput==1){
        var year1 = dateArr1[2];
        var year2 = dateArr2[2];
        var month1 = dateArr1[0];
        var month2 = dateArr2[0];
        var day1 = dateArr1[1];
        var day2 = dateArr2[1];
    }else{
        var year1 = dateArr1[2];
        var year2 = dateArr2[2];
        var month1 = dateArr1[1];
        var month2 = dateArr2[1];
        var day1 = dateArr1[0];
        var day2 = dateArr2[0];
    }
    var result = null;
    result = Number.compareFloat(year1, year2);
    if (result != 0) return result;
    result = Number.compareFloat(month1, month2);
    if (result != 0) return result;
    result = Number.compareFloat(day1, day2);
    if (result != 0) return result;
    return 0;
};

/**
* Compare two string date with the format dd mm yyy (eg: 01 Jan 2009)
*
* @lend Date
* @param {String} date1
* @param {String} date2
* @returns {Number} 0: Equal, < 0: Lest than, > 0: greater than
*/
Date.compareDate2 = function(date1, date2) {
    var format = /^\d{1,2}\s[A-Z][a-z]{2}\s[0-9]{4}$/;
    if (date1.search(format) == -1 || date2.search(format) == -1) throw 'Invalid Date';
    date1 = date1.split(' ');
    date2 = date2.split(' ');
    var shortMonth = {Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12};
    for( var key in shortMonth) {
        if (key == date1[1]) {
            date1[1] = shortMonth[key];
            break;
        }
    }
    for( var key in shortMonth) {
        if (key == date2[1]) {
            date2[1] = shortMonth[key];
            break;
        }
    }
    var result = null;
    result = Number.compareFloat(date1[2], date2[2]);
    if (result != 0) return result;
    result = Number.compareFloat(date1[1], date2[1]);
    if (result != 0) return result;
    result = Number.compareFloat(date1[0], date2[0]);
    if (result != 0) return result;
    return 0;
};

/**
* Convert a string to date value - format dd mmm yyy (eg: 01 Jan 2009)
*
* @lend Date
* @param {String} strDate
* @param {String} date2
* @returns {Number} 0: error, > 0: date value
*/
Date.toDate = function(strDate) {
    var format = /^\d{1,2}\s[A-Z][a-z]{3}\s[0-9]{4}$/;
    var resDate = new Date();
    if (strDate.search(format) == -1) return(0);
    strDate = strDate.split(' ');
    var shortMonth = {Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12};
    for( var key in shortMonth) {
        if (key == strDate[1]) {
            resDate.setMonth( shortMonth[key] );
            break;
        }
    }
    resDate.setDay(strDate[0]);
    resDate.setYear(strDate[2]);
    return resDate;
};

/**
* Display date as string
*
* @returns {String} dd mmm yyyy
*/
Date.prototype.toDateStringExt = function(){
    var shortMonth = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
    if (this.valueOf()==0) return('');
    return(this.getDate()+' '+shortMonth[this.getMonth()]+' '+this.getFullYear());
};

/**
* Display date/time as string
*
* @returns {String} dd mmm yyyy
*/
Date.prototype.toDateTimeString = function(){
    if (this.valueOf()==0) return('');
    return(this.toDateStringExt()+' '+this.getHours()+':'+this.getMinutes()+':'+this.getSeconds());
};

var msgTimeoutId = null;
/**
* Add more Class, functions for namespace Tut
*/
(function (){
    Object.extend(Tut, {
    	helper: [],
        /**
        * Get Token from current form
        *
        * @returns {String}
        */
        getToken: function() {
            return ('token=' + $('#token').val());
        },
        /**
        * Is response has error
        *
        * @param {String} response
        * @returns {Boolean}
        */
        isErrReq: function(response) {
            return (response.indexOf('WRN:') != -1);
        },
        /**
        * Is response has an synchronization data message
        *
        * @param {String} response
        * @returns {Boolean}
        */
        isSync: function(response) {
            return (response.indexOf('SYNC:') != -1);
        },
        /**
        * Check the data is a valid json format
        *
        * @param {String} data
        * @retuns {Boolean}
        */
        isJson: function(data) {
            return (data.search(/^(\{(.*)\}|\[(.*)\])$/) != -1 );
        },
        /**
        * Register hover event for image button
        *
        * @param {String} selector
        * @returns {void}
        */
        btnHover: function(selector) {
            return $(selector).hover(function() {
                this.src = this.src.replace(/(.gif|.jpeg)$/gi, '_on$1');
            }, function() {
                this.src = this.src.replace(/_on/g, '');
            });
        },
        /**
        * Display infomation message of acton
        *
        * @param (String} msg
        * @returns {void}
        */
        infoMsg: function(msg, redirectUrl) {
            redirectUrl = redirectUrl || ''; 
            $("#msg-area-cont").html(msg).show();
            $("#info_msg").css('top', Tut.getScrollY()).show();
            $(window).scroll(function () {
                $("#info_msg").css('top', Tut.getScrollY());
            });
            if (redirectUrl == '') {
                $('#msg-area-redirect').hide();
            } else {
                $('#msg-area-redirect').html(Js.redirecting).show();
            }
            msgTimeoutId = setTimeout(function() {
                $("#info_msg").hide();
                if (redirectUrl) location.href = redirectUrl;
            }, 2000);
        },
        infoMsg2: function(msg, idMsg, cssClass, closeMsg) {
            idMsg = idMsg || 'msg-info';
            cssClass = cssClass || 'msg-info2';
            idMsg = $('#' + idMsg);
            if (Object.isUndefined(closeMsg)) closeMsg = true;
            var css = idMsg.show().attr('class');
            if (!idMsg.hasClass(cssClass)) idMsg.removeClass().addClass(cssClass);
            idMsg.html(msg);
            if (closeMsg) setTimeout(function() {idMsg.hide().removeClass().addClass(css).html('');}, 2000);
        },
        getScrollY: function() {
            var scrollY = 0;
            if (document.documentElement && document.documentElement.scrollTop) {
                scrollY = document.documentElement.scrollTop;
            } else if(document.body && document.body.scrollTop) {
                scrollY = document.body.scrollTop;
            } else if(window.pageYOffset) {
                scrollY = window.pageYOffset;
            } else if(window.scrollY) {
                scrollY = window.scrollY;
            }
            return scrollY;
        },
		/**
        * Check if the current site is an Info Site
        * @param {Number}
        * @returns {Boolean}
        */
		isInfoSite: function(siteType) {
			return (siteType == 0);
		},
		/**
        * Get Cookie with the name applied
        *
        * @param {String} name
        * @returns {String|null}
        */
        getCookie: function(name) {
            if (document.cookie.length > 0) {
                var start = document.cookie.indexOf(name + "=");
                if (start != -1) {
                    start = start + name.length + 1;
                    var end = document.cookie.indexOf(";", start);
                    if (end == -1) end = document.cookie.length;
                    return unescape(document.cookie.substring(start, end));
                }
            }
            return null;
        },
        /**
         * Set cookie with value
         * 
         * @param {String} name
         * @Param {String} value
         * @param {Number} days
         * @returns {Object} Tut Object
         */
        setCookie: function(name, value, path, days) {
            days = (typeof days == 'undefined') ? 7 : days;
            path = path || '/';
            var date = new Date();
            date.setTime(date.getTime()+(days*24*60*60*1000));
            var expires = '; expires=' +date.toGMTString();
            document.cookie = name + '=' + value + expires + '; path=' + path;
            return this;
        },
		/**
		 * Set cookie with value
		 * 
		 * @param {String} name
		 * @Param {String} value
		 * @param {Number} days
		 * @returns {Object} Tut Object
		 */
		setCookie2: function(name, value, days) {
		    days = (typeof days == 'undefined') ? 7 : days;
		    var date = new Date();
		    date.setTime(date.getTime()+(days*24*60*60*1000));
		    var expires = "; expires="+date.toGMTString();
		    document.cookie = name+"="+value+expires+"; path=/";
		    return this;
		},
        /**
         * Delete the cookie
         * 
         * @param {String} name
         * @returns {Object} Tut object
         */
        deleteCookie: function(name, path) {
            this.setCookie(name, '', path, -1);
            return this;
        },
        /**
         * Ajax call
         * 
         * @param {Object} setting
         * @returns {Object} Tut Object
         */
        ajax: function(setting) {
            if (setting.data) setting.data += '&' + Tut.getToken();
            else setting.url += '&' + Tut.getToken();
            $.ajax(setting);
            return this;
        }
        //Add more functions, class for Tut .... here
    });
})();